package com.dyj.common.utils;

import org.springframework.core.io.ClassPathResource;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

/**
 * @author danmo
 * @date 2024-06-19 10:06
 **/
public class DecryptUtils {

    /**
     * 解密敏感数据
     *
     * @param encryptedData 敏感数据
     * @param sessionKey    对称解密秘钥
     * @param iv            对称解密算法初始向量
     * @return String
     * @throws NoSuchPaddingException             找不到填充方式
     * @throws NoSuchAlgorithmException           找不到算法
     * @throws InvalidAlgorithmParameterException 无效算法参数
     * @throws BadPaddingException                填充错误
     * @throws IllegalBlockSizeException          块大小错误
     * @throws InvalidKeyException                无效密钥
     */
    public static String decrypt(String encryptedData, String sessionKey, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] sessionKeyBytes = decoder.decode(sessionKey);
        byte[] ivBytes = decoder.decode(iv);
        byte[] encryptedBytes = decoder.decode(encryptedData);

        // JDK does not support PKCS7Padding, use PKCS5Padding instead
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec skeySpec = new SecretKeySpec(sessionKeyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
        byte[] ret = cipher.doFinal(encryptedBytes);
        return new String(ret);
    }

    /**
     * 解密手机号
     *
     * @param algorithm  算法
     * @param cipherText 密文
     * @param key        密钥
     * @param iv         初始向量
     * @return String
     * @throws NoSuchAlgorithmException           找不到算法
     * @throws NoSuchPaddingException             找不到填充方式
     * @throws InvalidKeyException                无效密钥
     * @throws InvalidAlgorithmParameterException 无效算法参数
     * @throws IllegalBlockSizeException          块大小错误
     * @throws BadPaddingException                填充错误
     */
    public static String decryptMobile(String algorithm, String cipherText, SecretKey key, IvParameterSpec iv)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        return new String(plainText);
    }

    public static PrivateKey loadRsaPrivateKey(String privateKeyPath) {
        ClassPathResource classPathResource = new ClassPathResource(privateKeyPath);
        if (!classPathResource.exists()) {
            return null;
        }
        try(InputStream inputStream = classPathResource.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader reader = new BufferedReader(inputStreamReader)) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.isEmpty()){
                    continue;
                }
                if (line.startsWith("-----")){
                    continue;
                }
                sb.append(line);
            }
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(sb.toString().getBytes(StandardCharsets.UTF_8)));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey prvKey = keyFactory.generatePrivate(keySpec);
            return prvKey;
        }catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e){
            e.printStackTrace();
        }
        return null;
    }

    public static PublicKey loadRsaPublicKey(String publicKeyPath) {
        ClassPathResource classPathResource = new ClassPathResource(publicKeyPath);
        if (!classPathResource.exists()) {
            return null;
        }
        try(InputStream inputStream = classPathResource.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader reader = new BufferedReader(inputStreamReader)) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.isEmpty()){
                    continue;
                }
                if (line.startsWith("-----")){
                    continue;
                }
                sb.append(line);
            }
            return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(sb.toString().getBytes(StandardCharsets.UTF_8))));
        }catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e){
            throw new RuntimeException(e);
        }
    }

    /**
     * sha256withRSA 签名
     * @param data
     * @param privateKey
     * @return
     */
    public static String sha256withRSASignature(String data, PrivateKey privateKey) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * sha256withRSA 验签
     * @param data
     * @param signStr
     * @param publicKey
     * @return
     */
    public static boolean sha256withRSAVerify(String data,String signStr, PublicKey publicKey) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initVerify(publicKey);
            sign.update(data.getBytes(StandardCharsets.UTF_8));
            return sign.verify(Base64.getDecoder().decode(signStr.getBytes(StandardCharsets.UTF_8)));
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
        String clientSecret = "0123456789abcdef0123456789abcdef";
        String encryptedMobile = "tyUWQwYuUmVFJtElAL+D7Q==";

        byte[] clientSecretBytes = clientSecret.getBytes();
        SecretKey secretKey = new SecretKeySpec(clientSecretBytes, 0, clientSecretBytes.length, "AES");

        byte[] iv = Arrays.copyOfRange(clientSecretBytes, 0, 16);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

        String algorithm = "AES/CBC/PKCS5Padding";

        String mobile = decryptMobile(algorithm, encryptedMobile, secretKey, ivParameterSpec);
        System.out.println(mobile);
    }
}
